import os

# import tarfile module to extracting map data
import tarfile

# import panda main module
import direct.directbase.DirectStart

from pandac.PandaModules import *

# functions and classes for reading the configuration file
import conf

# class that manages the map
class Map:
    def __init__(self, map_name):
        # extract the map files to the tmp directory.
        map_file = tarfile.open(os.path.join('maps', map_name + '.tar.gz'))
        map_file.extractall(os.path.join('tmp', 'map'))
        
        # read map info file
        self.info = conf.ReadConfig(os.path.join('tmp', 'map', 'info.txt'))
        
        # Generate terrain
        self.map_terrain = GeoMipTerrain('mySimpleTerrain')
        heightmap_path = os.path.join('tmp', 'map', 'heightmap.png')
        self.map_terrain.setHeightfield(heightmap_path)
        self.map_terrain.generate()
        # set the terrain block size
        self.map_terrain.setBlockSize(64)
        # set focal point and quality level
        self.map_terrain.setNear(5000) #?
        self.map_terrain.setFar(5000) #?
        # set terrain focal point
        self.map_terrain.setFocalPoint(base.camera)
        # get the nodepath of the terrain
        self.map_node = self.map_terrain.getRoot()
        # add nodepath to the render object
        self.map_node.reparentTo(render)
        # set the map size
        # 1 pixel on the .png image = 2 metres
        # ok but tell why
        self.map_node.setSx(4)
        self.map_node.setSy(4)
        self.map_node.setSz(self.info.z)
        # set terrain pos
        # why 100?
        map_x = -100 - self.info.width / 2
        map_y = -100 - self.info.height / 2
        map_z = self.info.underground
        self.map_node.setPos(map_x, map_y, map_z)
        
        # Skydrome
        self.skytexture = loader.loadTexture('textures/sky.jpg')
        self.skydrome = loader.loadModel('smiley.egg')
        self.skydrome.reparentTo(render)
        self.skydrome.setTwoSided(True)
        self.skydrome.setPos(0, 0, 0)
        self.skydrome.setScale(2000, 2000, 2000)
        self.skydrome.setTexture(self.skytexture, 1)
        self.skydrome.setTexScale(TextureStage.getDefault(), 1, 2)
        
        # Provvisorio solo per rendere la mappa decente
        tex = loader.loadTexture('textures/grass.jpg')
        ts = TextureStage('ts')
        self.map_node.setTexture(ts, tex, 1)
        self.map_node.setTexScale(ts, 64, 64)
        
        # add objects to the map
        self.loaded_models = {}
        
        # list of the model that must be loaded
        modelsToLoad = conf.read_values(os.path.join('tmp', 'map', 'objects.txt'))
        for (x, y, z, name) in modelsToLoad:
            modelpath = os.path.join('models', name)
            
            if not self.loaded_models.has_key(name):
                try:
                    self.loaded_models[name] = loader.loadModel(modelpath+'.egg')
                except:
                    self.loaded_models[name] = loader.loadModel(modelpath+'.egg.pz')
            
            self.loaded_models[name].reparentTo(render)
            self.loaded_models[name].setPos(int(x), int(y), int(z))
    
    def pixy_to_xy(self, pix_x, pix_y):
        'From map pixel to global (x, y) coordinates.'
        raise NotImplementedError
    
    def xy_to_pixel(self, x, y):
        'From global (x, y) coordinates to map pixel.'
        pix_x = (100 + self.info.width/2 + x) / 4
        pix_y = (100 + self.info.height/2 + y) / 4
        return pix_x, pix_y

    def elevation(self, x, y):
        "Returns the elevation of the given terrain in metres from the 0 on z axis."
        # positions in pixels
        pix_x, pix_y = self.xy_to_pixel(x, y)
        # terrain elevation
        elevation = self.map_terrain.getElevation(pix_x, pix_y) * self.info.z
        # height on z axis
        z = elevation + self.info.underground
        return z
        
